package services

import (
	"encoding/json"
	"fmt"
	"gitee.com/phpdi/ant-api/entitys"
	"gitee.com/phpdi/ant-api/utils"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"github.com/astaxie/beego/orm"
	"io/ioutil"
	"strings"
)



//权限服务
type permService struct {
	permsCacheKey    string //所有的权限数据缓存键
	permTreeCacheKey string //权限树结构缓存键
	filePath         string //权限树文件路径
	userPermCachePrefix string            //用户缓存前缀
}

//权限服务单例对象
var PermService *permService
func init()  {
	PermService=NewPerm()
}



//构造函数
func NewPerm() *permService {
	this := &permService{
		permsCacheKey:    "permsCacheKey",
		permTreeCacheKey: "permTreeCacheKey",
		filePath:         "conf/permtree.json",
		userPermCachePrefix:"userPermCachePrefix:",
	}

	return this
}


//获取所有的权限树
func (this *permService) GetAllPermTree(name string) []entitys.PermTree {
	var res []entitys.PermTree
	for _, v := range this.getPermTrees() {
		treeLevel2 := v

		treeLevel2.SubPermTree = []entitys.PermTree{}
		for _, v1 := range v.SubPermTree {
			treeLevel3 := v1

			treeLevel3.SubPermTree = []entitys.PermTree{}

			for _, v2 := range v1.SubPermTree {

				if name == "" || strings.Contains(v.Name, name) || strings.Contains(v1.Name, name) || strings.Contains(v2.Name, name) {
					treeLevel3.SubPermTree = append(treeLevel3.SubPermTree, v2)
				}
			}

			if len(treeLevel3.SubPermTree) > 0 {
				treeLevel2.SubPermTree = append(treeLevel2.SubPermTree, treeLevel3)
			}
		}

		if len(treeLevel2.SubPermTree) > 0 {
			res = append(res, treeLevel2)
		}
	}

	return res
}



//通过用户id获取权限数据 含缓存层
func (this *permService) GetPermUrlsByUserId(userId uint32) []string {
	//缓存前缀
	permUrls := []string{}
	if userId == 0 {
		return permUrls
	}

	_= RememberCache(fmt.Sprintf("%s%d",this.userPermCachePrefix ,userId), &permUrls,86400, func() interface{} {
		var (
			cpermUrls []string
			perms []entitys.Perm
			err error
		)
		//从数据库获取权限数据
		if perms ,err= this.getPermsByUserId(userId);err!=nil {
			logs.Info("通过用户id获取权限数据:",err)
			return cpermUrls
		}

		for _, v := range perms {
			cpermUrls = append(cpermUrls, v.PermUrl)
		}

		return cpermUrls

	})

	return permUrls

}

//通过角色id刷新用户缓存
func (this *permService) FlushUserPermsCacheByRoleId(roleId uint32) {
	var roleUsers []entitys.RoleUser
	_, _ = Orm().QueryTable(TableName("role_user")).Filter("role_id", roleId).All(&roleUsers)

	for _, v := range roleUsers {
		_ = CacheService.Delete(fmt.Sprintf("%s%d",this.userPermCachePrefix ,v.UserId))
	}

}

//刷新所有用户的权限缓存数据
func (this *permService) FlushUserPermsCache() {
	var users []entitys.User
	_, err := Orm().QueryTable(TableName("user")).Limit(-1).All(&users)
	if err != nil {
		beego.Info("刷新所有用户的权限缓存数据,错误:", err)
	}

	for _, v := range users {
		this.FlushUserPermsCacheByUserId(v.Id)
	}

}

//通过用户id刷新用户权限
func (this *permService) FlushUserPermsCacheByUserId(userId uint32) {
	_ = CacheService.Delete(fmt.Sprintf("%s%d",this.userPermCachePrefix ,userId))
}

//判定用户是否拥有权限
func (this *permService) HasPerm(user entitys.User, permUrl string) bool {

	//超级用户判定
	if user.IsSuper==entitys.IsSuper {
		return true
	}

	//在权限表中无数据,判定为有权限访问
	var isPermUrl = false
	for _, v := range this.getPerms() {
		if v.PermUrl == permUrl {
			isPermUrl = true
			break
		}

	}

	//权限表中未设置权限
	if !isPermUrl {
		return true
	}

	//判定权限
	return utils.InArray(permUrl, this.GetPermUrlsByUserId(user.Id))

}



//获取所有的权限数据
func (this *permService) getPerms() []entitys.Perm {
	var (
		res []entitys.Perm
		err error
	)

	err = RememberCache(this.permsCacheKey, &res, 86400*10, func() interface{} {
		var perms []entitys.Perm
		if _, err := Orm().QueryTable(TableName("perm")).Limit(-1).All(&perms); err != nil {
			logs.Error("查询权限表数据失败：%s.", err.Error())
		}

		return perms
	})

	if err != nil {
		beego.Info("permService.getPerms 错误：", err)
	}

	return res
}

//获取权限树结构
func (this *permService) getPermTrees() []entitys.PermTree {
	var (
		res []entitys.PermTree
		err error
	)

	err = RememberCache(this.permTreeCacheKey, &res, 86400*10, func() interface{} {
		var (
			permTree []entitys.PermTree
			err      error
			content  []byte
		)

		//配置文件中基础权限树
		if content, err = ioutil.ReadFile(this.filePath); err != nil {
			beego.Info("permService.getPermTrees 错误：", err)
			return permTree
		}

		if err = json.Unmarshal(content, &permTree); err != nil {
			beego.Info("permService.getPermTrees 错误1：", err)
			return permTree
		}

		//动态的树结构
		for k, _ := range permTree {
			for k1, v1 := range permTree[k].SubPermTree {
				permTree[k].SubPermTree[k1].SubPermTree = this.getPermTreeByPermTreeId(v1.Id)
			}
		}

		return permTree
	})

	if err != nil {
		beego.Info("permService.getPermTrees 错误：", err)
	}

	return res
}

//通过module获取树结构
func (this *permService) getPermTreeByPermTreeId(permTreeId uint32) []entitys.PermTree {
	var subTree []entitys.PermTree

	var perms []entitys.Perm
	_, _ = Orm().QueryTable(TableName("perm")).Filter("permtree_id", permTreeId).OrderBy("sort").All(&perms)

	for _, v := range perms {
		subTree = append(subTree, entitys.PermTree{
			Id:             v.Id,
			Name:           v.Name,
		})
	}

	return subTree
}

//刷新权限缓存
func (this *permService) flushPermCache() {
	var err error
	if err = CacheService.Delete(this.permTreeCacheKey); err != nil {
		beego.Info("permService.flushPermCache 错误：", err)
	}

	if err = CacheService.Delete(this.permsCacheKey); err != nil {
		beego.Info("permService.flushPermCache 错误：", err)
	}
}


//通过角色获取权限数据,支持多角色
func (this *permService) GetPermsByRoleId(roleIds ...uint32) (perms []entitys.Perm,err error) {
	var (
		roles []entitys.Role
		roleIdStr string
	)

	if len(roleIds)== 0 {
		return
	}

	if _,err = Orm().QueryTable(TableName("role")).Filter("id__in", roleIds).Filter("Enable", true).Limit(-1).All(&roles);err!= nil {
		return
	}

	for _, v := range roles {
		roleIdStr += fmt.Sprintf("%d,",v.Id)
	}
	roleIdStr = strings.TrimRight(roleIdStr, ",")
	if roleIdStr == "" {
		return
	}

	//构建查询器
	qb, _ := orm.NewQueryBuilder("mysql")
	qb.Select("p.id", "p.name", "p.perm_url", "p.module_id").
		From(TableName("perm") + " as p").
		InnerJoin(TableName("role_perm") + " as rp").On("rp.perm_id = p.id").
		Where(fmt.Sprintf("rp.role_id in (%s)", roleIdStr)).
		GroupBy("p.id")

	// 执行 SQL 语句
	_, err = Orm().Raw(qb.String()).QueryRows(&perms)

	return
}

//通过用户Id获取权限信息
func (this *permService) getPermsByUserId(userId uint32) (perms []entitys.Perm,err error) {
	var (
		roles []entitys.Role

	)
	if roles,err= RoleService.GetRolesByUserId(userId);err!= nil {
		return
	}

	var roleIds []uint32
	for _, v := range roles {
		roleIds = append(roleIds, v.Id)
	}

	if len(roleIds) == 0 {
		return
	}

	return this.GetPermsByRoleId(roleIds...)

}